fix: preserve thought_signature across tool-call turns (fixes Gemini 3.x tool use) - #21
Open
FritzHeider wants to merge 1 commit into
Open
Conversation
Gemini 3.x rejects a replayed function call whose thought_signature is missing, so the agent dies on its second step with: 400 INVALID_ARGUMENT: Function call is missing a thought_signature in functionCall parts. This is required for tools to work correctly. Additional data, function call `default_api:goto_tool`, position 2. The Google provider already handles both ends of this: it extracts the signature from the response (providers/google/llm.py:321) and replays it onto the function-call Part when rebuilding history (:121). The gap was in between — the agent constructed its ToolMessage without thinking or thinking_signature, so the extracted value was discarded before it could be replayed, and ToolMessage.thinking_signature was never populated by anything. Thread both fields from the LLMEvent into the ToolMessage. This also affects the Anthropic provider, which reads the same msg.thinking_signature (providers/anthropic/llm.py:148,160) that nothing previously set, so extended thinking with tools should benefit too (verified on Gemini only). Verified with gemini-flash-latest: before this change the agent fails at step 2; after it, a multi-step navigate-and-extract task completes.
PR Summary by QodoFix: preserve thought_signature when recording tool-call turns
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTo customize comments, go to the Qodo configuration screen, or learn more in the docs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gemini 3.x rejects a replayed function call whose
thought_signatureis missing, so the agent dies on its second step:Step 1 succeeds (the browser navigates), then every retry fails and the run aborts. This makes the agent unusable on current Gemini models —
gemini-2.5-flashandgemini-2.0-flashnow return404 ... no longer available to new usersfor new API keys, so new users land on a 3.x model by default.Root cause
The Google provider already handles both ends of this:
src/providers/google/llm.py:321(_extract_thought_signature, intoThinking(signature=...))Partwhen rebuilding history —src/providers/google/llm.py:121-126The gap is between them.
src/agent/service.pybuilt itsToolMessagefrom theLLMEventwithoutthinkingorthinking_signature, so the extracted signature was discarded before it could ever be replayed.ToolMessage.thinking_signatureis declared insrc/messages/service.py:150but nothing assigned it anywhere in the codebase.Fix
Thread both fields from the
LLMEventinto theToolMessage(2 lines).Also affects Anthropic
src/providers/anthropic/llm.py:148,160reads the samemsg.thinking_signaturethat nothing previously set, so extended thinking with tools was likely broken in the same way. This fix is provider-agnostic and should repair that path too — though I verified on Gemini only.Verification
With
gemini-flash-latest:Happy to add a regression test if you would like one — a fake provider returning a signature and asserting it survives the history round-trip would cover it.